
/*
 * Este programa ordena una lista de numeros mediante el algoritmo de MergeSort.
 * El procesamiento de este programa es realizado en forma paralela.
 */

/* Inclusión de bibliotecas propias */
#include "coordinador/coordinador.h"
#include "nodo/nodo.h"
#include "varios/mpi-utiles.h"

/* Inclusión de bibliotecas estandares */
#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>


/* Sección de implementación de funciones */

int main(int argc, char **argv) {

    // Iniciamos la librería mpi
    MPI_Init(&argc, &argv);

    double inicio; // Timestamp en el que el nodo inició
    double fin; // Timestamp en el que el nodo terminó su procesamiento
    double tiempoInactivoNodo = 0; // Tiempo total de inactividad de los nodos
    double tiempoInactivoCoord = 0; // Tiempo en el que el nodo coordinador estuvo inactivo
    double tiempoNoContable = 0; // Tiempo en que el coordinador tarda en generar los datos necesarios
        
    // Verificar nuestro ranking dentro del comunicador global
    int globalRank; // Ranking en el comunicador global
    MPI_Comm_rank(MPI_COMM_WORLD, &globalRank);

    // Obtenemos el momento inicial de todos los nodos al mismo tiempo
    MPI_Barrier(MPI_COMM_WORLD);
    inicio = MPI_Wtime();
    
    // Ejecutamos la logica correspondiente a nuestro nodo
    if(globalRank == 0) {
        double *tiempos = coordinador();
        tiempoNoContable = tiempos[0];
        tiempoInactivoCoord = tiempos[1];
        free(tiempos);
    } else {
        tiempoInactivoNodo = nodo();
    }

    // Registramos elmomento de finalizacion de cada nodo
    fin = MPI_Wtime();
    MPI_Barrier(MPI_COMM_WORLD);
    
    // Obtenemos los datos de tiempos de cada nodo de trabajo
    double *bufferCoord = NULL;
    double bufferNodos[2];
    if (globalRank==0) {
        bufferCoord = malloc(sizeof(double)*(obtenerCantidadDeNodosDeTrabajo()+1)*2);
    } else {
        bufferNodos[0] = tiempoInactivoNodo;
        bufferNodos[1] = fin-inicio;
    }
    MPI_Gather(bufferNodos, 2, MPI_DOUBLE, bufferCoord, 2, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    
    // Tenemos en bufferCoord los datos de rendimiento de los nodos de trabajo, los procesamos
    if (globalRank==0) {
        
        double tiempoTotalCoord = fin-inicio-tiempoNoContable;
        double ocupacion = 100 * (tiempoTotalCoord-tiempoInactivoCoord) / tiempoTotalCoord;
        
        printf("El nodo 0 estuvo %.2f segundos inactivos de un total de %.2f segundos. %.2f%% de ocupacion\n",
                tiempoInactivoCoord, tiempoTotalCoord, ocupacion);
        
        int i;
        for (i=1; i<=obtenerCantidadDeNodosDeTrabajo(); i++) {
            
            double tiempoTotalNodo = bufferCoord[(i*2)+1];
            double tiempoInactivo = (tiempoTotalCoord-tiempoTotalNodo) + bufferCoord[i*2];
            double ocupacion = 100 * (tiempoTotalCoord-tiempoInactivo ) / tiempoTotalCoord;
            
            printf("El nodo %d estuvo %.2f segundos inactivos de un total de %.2f segundos. %.2f%% de ocupacion\n",
                    i, tiempoInactivo , tiempoTotalCoord, ocupacion);
            
        }
        
        printf("Tiempo total de procesamiento: %.2f", tiempoTotalCoord);
    }
    
    // Finalizamos la librería de MPI
    MPI_Finalize();
    return (EXIT_SUCCESS);

}
